package com.shiliuzi.www.interceptor;

import com.shiliuzi.www.common.Code;
import com.shiliuzi.www.pojo.bo.UserInfoBo;
import com.shiliuzi.www.util.CommonUtil;
import com.shiliuzi.www.util.LimitUtil;
import com.shiliuzi.www.util.RedisUtil;
import com.shiliuzi.www.util.userUtil.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.shiliuzi.www.common.Prefix.LOGIN_USER_TOKEN;

/**
 * 第一层拦截器
 * 判断用户是否登录/在线
 */
@Slf4j
@Component
//TODO 同一用户禁止多台登录
public class UserInterceptor implements HandlerInterceptor {

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private CommonUtil commonUtil;

    @Resource
    private LimitUtil limitUtil;

    @Resource
    private RedisUtil<String> redisUtil;

    private static String requestRecord = "";

    public static final ExecutorService pool = Executors.newSingleThreadExecutor();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        request.getParameterMap().forEach((key,value)->{
            System.out.println(key+" "+value);
        });
        System.out.println(request.getRequestURL()+" "+request.getRequestURI());

        String token = request.getHeader(jwtUtil.getHeader());

        if(!judgeToken(token,response)) return false;

        if(!judgeRedis(token,response)) return false;

        if(saveUser(token)==null) return false;

        pool.execute(()->clearLimit(request.getRequestURI()));

        return refresh(token,response);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserInfoBo.removeUser();
    }

    /**
     * 判断token是否合理化
     * @param token
     * @param response
     * @return
     */
    public boolean judgeToken(String token, HttpServletResponse response){
        if (!StringUtils.hasLength(token) || !jwtUtil.verifyToken(token)) {
            response.setStatus(Code.BUE_USER_LOGIN_ERR);
            log.info("请求头为空！该用户未登录！");
            return false;
        }
        return true;
    }

    /**
     * 判断token是否和redis中存储一致
     * @param token
     * @param response
     * @return
     */
    public boolean judgeRedis(String token, HttpServletResponse response) {
        String redisToken = redisUtil.getRedis(LOGIN_USER_TOKEN + token, String.class);
        if(redisToken == null || !redisToken.equals(token)) {
            response.setStatus(Code.BUE_USER_LOGIN_ERR);
            log.info("redis中不存在该用户！请重新登录！");
            return false;
        }
        return true;
    }

    /**
     * 存储user到TreadLocal
     * @param token
     * @return
     */
    public UserInfoBo saveUser(String token) {
        UserInfoBo userInfoBo = jwtUtil.getUserInfo(token);
        UserInfoBo.saveUser(userInfoBo);
        return UserInfoBo.obtainUser();
    }

    /**
     * 刷新令牌和redis的有效期，并删除redis原有token
     * @param token
     * @param httpServletResponse
     * @return
     */
    @Transactional
    public boolean refresh(String token, HttpServletResponse httpServletResponse) {
        Date nowDate = new Date();
        try {
            String refreshToken = jwtUtil.refreshToken(token, nowDate, commonUtil.expireDate(nowDate, 60 * 10l));
            httpServletResponse.setHeader("Authorization",refreshToken);
//            redisUtil.expireRedis(LOGIN_USER_TOKEN + refreshToken,10l,TimeUnit.MINUTES);
//            redisUtil.delRedis(LOGIN_USER_TOKEN + token);
        } catch (Exception e) {
            log.error("没有确保刷新令牌和redis成功！系统内部出错！请稍后再试！");
            return false;
        }
        return true;
    }

    /**
     * 限制器重置机制，url不一致则更新
     * @param uri
     */
    public void clearLimit(String uri) {
        while(true) {
            try {
                if(!requestRecord.equals(uri)) limitUtil.clearLimit();
                requestRecord = uri;
                break;
            } catch (Exception e) {
                log.info("限制器更新出错！请尽快处理！");
                continue;
            }
        }
    }
}
